参数高效微调:LoRA、QLoRA 与 Adapter
训练大模型有两条正交的省资源路线:分布式(多切几张卡,见 02-分布式训练总论与显存账本)与只训一小部分参数(PEFT)。
这一篇讲后者 —— 它的核心假设只有一句:微调不需要更新所有参数。
全量微调的显存账
| 组成部分 | BF16 下的显存 | 7B | 70B |
|---|---|---|---|
| 模型参数 | 14 GB | 140 GB | |
| 梯度 | 14 GB | 140 GB | |
| Adam 两个状态( | 56 GB | 560 GB | |
| 激活值 | 随 batch / 序列长度 | 约 10–30 GB | 约 100–300 GB |
| 合计 | 约 | 约 100 GB | 约 1 TB |
这张表少了一项
来源给的是
两处口径的差异就这一行,引用时注意。这里保留来源的
无论按哪个口径,结论一样:一块 A100 80 GB 连全量微调 7B 都勉强,70B 要 16+ 块卡。
PEFT 的核心假设
全量微调把参数从
具有低维结构 —— 它可以用远少于 个参数表示。
不同的 PEFT 方法,本质上是对
理论依据来自 Aghajanyan et al.(2020):预训练模型微调时的内在维度(Intrinsic Dimensionality)远低于参数空间的实际维度 —— 数百万参数的模型,微调的有效自由度可能只有几千。
LoRA
核心假设:
训练时
两个实现细节
| 细节 | 做法 | 为什么 |
|---|---|---|
| 初始化 | 保证训练开始时 | |
| 缩放因子 | 实际用 | 控制 LoRA 更新的幅度。 |
参数量( 的线性层)
| 方法 | 可训练参数 | 占比 |
|---|---|---|
| 全量微调 | 16.7 M | 100% |
| LoRA( | 65 K | 0.39% |
| LoRA( | 131 K | 0.78% |
| LoRA( | 524 K | 3.1% |
用在哪几层
该文只在
在所有线性层上都应用("full LoRA")通常效果更好,尤其在复杂任务上。LLaMA-Factory 等工具默认对所有线性层应用。
这里的「所有线性层」指 Q/K/V/O 投影 + SwiGLU FFN 的三个投影(
推理时合并:零额外开销
合并后的模型与全量微调在推理时完全等价 —— 相同架构、相同计算量、相同速度。所以 LoRA 是一个「训练省显存、推理零代价」的方案。
再加一条工程优势:可以为不同任务训不同的 adapter,按需加载与切换 —— 每个只要几十到几百 MB,不必存整份模型副本。
低秩约束不只是省参数,还起正则化作用。 它限制了模型的更新自由度,降低小数据集上的过拟合风险 —— 这也是 LoRA 在数据量少时往往优于全量微调的原因之一。
怎么选
| 任务 | |
|---|---|
| 简单(情感分类、格式调整) | 8 |
| 中等(指令微调、对话) | 16 – 32 |
| 复杂(数学推理、代码生成) | 64 或更高 |
LoRA 把
输入 x
│
┌─────────┴─────────┐
▼ ▼
┌──────────┐ ┌──────────┐
│ W₀ │ │ A (r×k) │ 随机高斯初始化
│ 冻结不动 │ └────┬─────┘
└────┬─────┘ ▼
│ ┌──────────┐
│ │ B (d×r) │ 初始化为零 ⇒ 训练开始时 ΔW = BA = 0
│ └────┬─────┘ (模型行为与预训练完全一致)
│ │ 整体乘 α/r
└────────┬─────────┘
▼
h = W₀x + (α/r)·BAx
⇒ 只训 A 与 B,W₀ 不动
⇒ r ≪ min(d, k):d = 4096 的层在 r = 8 时可训练参数只有原来的 0.39%
⇒ 推理时合并成 W = W₀ + (α/r)BA ⇒ 架构、计算量、速度与全量微调完全一致QLoRA
LoRA 的漏洞:虽然只训少量参数,但前向传播仍需完整模型 —— 70B 的
QLoRA(Dettmers et al., 2023)把冻结的
三个关键创新
| 创新 | 内容 |
|---|---|
| NF4(NormalFloat 4-bit) | 传统 4-bit 量化把值域均匀分 16 段;但预训练权重近似正态分布(大部分集中在零附近)。NF4 按正态分布的分位数定区间,使每段包含大致相同数量的权重,最小化量化误差 |
| 双重量化 | 每个量化块要存一个 FP32 缩放因子。块大小 64 时开销 |
| 分页优化器 | 利用 NVIDIA Unified Memory,让优化器状态在 GPU 显存与 CPU 内存间自动分页 —— 显存不足时换出,需要时换入 |
NF4 按正态分布的分位数定区间(与传统均匀分箱对照):
传统 4-bit:把值域均匀切成 16 段
┌──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┬──┐
│ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │
└──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┴──┘
↑ 零附近被分到和两端一样多的「格位」,但那里的权重远比两端密
NF4:按正态分布的分位数定区间 ⇒ 每段包含大致相同数量的权重
┌┬─┬──┬───┬────┬─────┬──────┬───────┬──────────┐
└┴─┴──┴───┴────┴─────┴──────┴───────┴──────────┘
密(零附近区间窄) 疏(尾部区间宽)
⇒ 预训练权重近似正态分布,所以按分位数分箱比均匀分箱的量化误差更小
双重量化:每个量化块还要存一个 FP32 缩放因子(块大小 64)
⇒ 4/64 = 0.0625 字节/参数 —— 70B 上就是 4.4 GB
⇒ 把缩放因子本身也量化到 8-bit ⇒ 降到 0.0156 字节/参数显存对比
| 配置 | 7B | 70B |
|---|---|---|
| 全量微调(BF16) | 约 100 GB | 约 1 TB |
| LoRA(BF16 模型) | 约 15 GB | 约 145 GB |
| QLoRA(NF4 + LoRA) | 约 6 GB | 约 48 GB |
QLoRA 让单卡 24 GB(如 RTX 4090)微调 7B、单卡 A100 80 GB 微调 70B 成为可能。
效果与代价
效果:该文报告 4-bit QLoRA 微调的效果与 16-bit 全量微调接近。Guanaco(QLoRA 微调 LLaMA-65B)在 Vicuna 基准上达到 ChatGPT 的 99.3%。
机制解释:量化损失被 LoRA 补偿了 —— LoRA 训练的参数是 BF16 精度的,它们能「修正」4-bit 量化引入的误差。
代价:
QLoRA 训练比 BF16 LoRA 慢 30–50%
4-bit 权重每次前向都要反量化回 BF16 —— 这就是它省显存的代价。显存够(比如多卡)时,BF16 LoRA 是更快的选择;QLoRA 的价值是「显存极其有限时仍能训」。
其他路线
Adapter(Houlsby et al., 2019)
在 Transformer 每个子层之后插入一个小瓶颈网络:
与 LoRA 的差别:Adapter 改结构(新增模块),LoRA 改权重(在既有层上加增量)。前者推理时有额外计算,后者没有。
Prompt-based:软提示
| 方法 | 做法 |
|---|---|
| Prefix-Tuning(Li & Liang, 2021) | 在每层 Self-Attention 里前置一组可学习的虚拟 token,扩 K/V: |
| P-Tuning v2(Liu et al., 2022) | 在每一层都加可学习 prefix(而非只在输入层),并在更多任务类型上验证 |
为什么式微:
- 有效容量有限 —— prefix 通常只有 10–100 个 token,能编码的任务信息有限
- 占上下文窗口 —— 推理时减少可用的输入长度
- 效果不及 LoRA —— 在大模型上几乎全面落后
综合对比
| 方法 | 可训练参数 | 推理额外开销 | 显存 | 效果 | 现状 |
|---|---|---|---|---|---|
| 全量微调 | 100% | 无 | 极高 | 最好(上限) | 有资源时首选 |
| LoRA | 0.1–3% | 零(可合并) | 中 | 接近全量 | 当前主流 |
| QLoRA | 0.1–3% | 零(合并后) | 极低 | 接近 LoRA | 显存受限时首选 |
| Adapter | 0.5–5% | 有(额外层) | 中 | 接近全量 | 已被 LoRA 取代 |
| Prefix-Tuning | < 0.1% | 有(增序列长) | 低 | 低于 LoRA | 已少用 |
选型只看一个问题:显存够不够。
显存充足(多卡 / A100 / H100) → 全量微调(效果上限)
显存有限但够放 BF16 权重 → LoRA(效果与速度的平衡)
单卡 ≤ 24 GB → QLoRA(NF4 + LoRA)实践
超参数
| 参数 | 推荐 | 说明 |
|---|---|---|
lora_rank | 8 – 64 | 简单任务小、复杂任务大 |
lora_alpha | 控制更新缩放 | |
lora_dropout | 0.05 – 0.1 | 正则化 |
target_modules | 所有线性层 | q/k/v/o_proj + gate/up/down_proj |
learning_rate | 比全量微调高一个量级 | |
epochs | 2 – 5 | 数据少时可多跑几轮 |
变体
| 变体 | 改动 |
|---|---|
| DoRA | 把权重分解为幅度 + 方向,只对方向部分用 LoRA |
| LoRA+ | 对 |
| rsLoRA | 缩放因子从 |
| AdaLoRA | 动态分配 rank —— 重要的层给高 rank,不重要的给低 rank 甚至剪枝 |
多任务与组合
一个基础模型训多个 LoRA(中文对话 / 代码 / 医疗…),推理时按需加载 —— 基础模型只存一份。
更进一步,多个 LoRA 可以线性组合:
不重新训练就能组合多个能力。
这条与 06-vLLM 部署、参数与服务特性 里的 Multi-LoRA 服务是同一件事的两端:训练侧产出多个 adapter,服务侧在同一个引擎里动态加载切换。LoRA 的「可组合」是它区别于其他 PEFT 方法的工程价值。
工具
| 工具 | 特点 |
|---|---|
| PEFT(Hugging Face) | LoRA / QLoRA / Prefix-Tuning,与 Transformers 深度集成 |
| LLaMA-Factory | 全流程(SFT / RLHF / DPO)+ Web UI |
| Unsloth | 自定义 Triton kernel,号称提速 2–5× |
| Axolotl | YAML 配置驱动,多数据格式 |
| TRL(Hugging Face) | RLHF / DPO,与 PEFT 结合 |
相关
- 05-优化器与显存开销 —— 全量微调
账本的完整推导 - 12-FFN 与激活函数 —— 低秩分解的数学基础与 SwiGLU 的三个投影
- 08-量化 —— NF4 / INT4 量化的机制与坑
- 06-vLLM 部署、参数与服务特性 —— 服务侧的 Multi-LoRA
- 02-分布式训练总论与显存账本 —— 另一条正交的省资源路线
- 17-Agentic RL —— SFT / RL 的训练流程
参考
- https://arxiv.org/abs/2106.09685
- https://arxiv.org/abs/2305.14314
- https://arxiv.org/abs/1902.00751
- https://arxiv.org/abs/2101.00190
- https://arxiv.org/abs/2110.07602
- https://arxiv.org/abs/2012.13255
- https://arxiv.org/abs/2402.09353 | rsLoRA:https://arxiv.org/abs/2312.03732
- ting.is-a.dev. LLM 原理 专栏第 05 篇.
该篇的「
YJ